package com.pzl.datepicker;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ArgbEvaluator;
import android.animation.FloatEvaluator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.widget.Scroller;

/**
 * Created by zl.peng on 2016-05-06.
 */
public class DatePicker extends View {
    private final String TAG = "DatePicker";
    private IDatePicker mIDatePicker;
    private String[] yearArray = new String[60];// 前后一共60年
    private String[] monthArray = new String[]{"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
    private String[] dayArray = new String[]{"01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22",
            "23", "24", "25", "26", "27", "28", "29", "30", "31"};
    private int[] maxDayArray = new int[]{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

    private int mSelectedDay;
    private int mSelectedMonth;
    private int mSelectedYear;

    private Paint mPaint;
    private TextPaint mTextPaint;
    private String mLabel;
    private int mLabelHeight;
    private float mLabelSize;
    private float mMinSize;
    private float mMaxSize;

    /**
     * 中间数字大小
     */
    private float mCenterSize_Year;
    private float mCenterSize_Month;
    private float mCenterSize_Day;
    private float mPreNextSize_Year;
    private float mPreNextSize_Month;
    private float mPreNextSize_Day;
    private float mDeltaSize;
    /**
     * 1:up
     * -1:down
     */
    private int mDirection;

    private int mMeasuredHeight;
    private int mMeasuredWidth;
    /**
     * 距右边margin
     */
    private int mRightGap = 5;
    /**
     * 被选择的day,month,year左右margin
     */
    private int mMargin = 40;
    /**
     * 计算常
     */
    private int mPreNextHeight;
    /**
     * dividor布局比例
     */
    private final float mHeightRat = 0.22f;

    /**
     * 滚动更新的距离(常)
     */
    private int mUpdateScroll;

    private int mCurScroll_Year;
    private int mCurScroll_Month;
    private int mCurScroll_Day;

    private int mYearMaxWidthDefault;
    private int mMonthMaxWidthDefault;
    private int mDayMaxWidthDefault;

    private String[] mDrawYear = new String[5];
    private String[] mDrawMonth = new String[5];
    private String[] mDrawDay = new String[5];

    private int mOldY, mNewY;

    private FloatEvaluator mFloatEvaluator;
    private ArgbEvaluator mArgbEvaluator;

    private Rect mRect_Year_Center;
    private Rect mRect_Year_Pre;
    private Rect mRect_Year_Next;
    private Rect mRect_Year_Min;

    private Rect mRect_Month_Center;
    private Rect mRect_Month_Pre;
    private Rect mRect_Month_Next;
    private Rect mRect_Month_Min;

    private Rect mRect_Day_Center;
    private Rect mRect_Day_Pre;
    private Rect mRect_Day_Next;
    private Rect mRect_Day_Min;


    private int mAnimColor1_Year;
    private int mAnimColor2_Year;
    private int mAnimColor1_Month;
    private int mAnimColor2_Month;
    private int mAnimColor1_Day;
    private int mAnimColor2_Day;

    /**
     * 设置的未选中的颜色
     */
    private int mColorPreNext;
    /**
     * 默认选中的颜色
     */
    private int mSelectedColor = Color.BLACK;
    private int mDividorColor = Color.BLACK;

    private ValueAnimator valueAnimator_Year, valueAnimator_Month, valueAnimator_Day;
    private int mAnimDuration = 200;

    private VelocityTracker mVelocityTracker;
    private float mLastXVelocity;
    private Scroller mScroller;
    private int mFillingDy;
    private int mOldFilling;
    private int mNewFilling;
    private MotionEvent mEvent;

    /**
     * 是否正在执行（调整居中）动画
     */
    private boolean mIsAdjustingAnim_Year = false;
    /**
     * 是否正在执行（调整居中）动画
     */
    private boolean mIsAdjustingAnim_Month = false;
    /**
     * 是否正在执行（调整居中）动画
     */
    private boolean mIsAdjustingAnim_Day = false;

    /**
     * 1:down 2:move 3:up
     */
    private int mTouchMode = 3;
    private boolean mIsFilling = false;
    /**
     * 用户选择交互的picker(1:day 2:month 3:year)
     */
    private int mInteractivePicker = 0;

    /**
     * 显示外部设置的date
     */
    private boolean mShowSet = false;

    public DatePicker(Context context) {
        this(context, null);
    }

    public DatePicker(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public DatePicker(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        TypedArray ta = context.getTheme().obtainStyledAttributes(attrs, R.styleable.DatePicker, 0, 0);
        mLabel = ta.getString(R.styleable.DatePicker_label) == null ? "" : ta.getString(R.styleable.DatePicker_label);
        mLabelSize = ta.getDimension(R.styleable.DatePicker_labelSize, 12);
        mColorPreNext = ta.getColor(R.styleable.DatePicker_colorPreNext, Color.GRAY);
        mMinSize = ta.getDimension(R.styleable.DatePicker_minSize, 12);
        mMaxSize = ta.getDimension(R.styleable.DatePicker_maxSize, 12);
        mMargin = (int) ta.getDimension(R.styleable.DatePicker_spacing, 40);
        mDeltaSize = mMaxSize - mMinSize;
        ta.recycle();

        mVelocityTracker = VelocityTracker.obtain();
        mScroller = new Scroller(context);

        mPaint = new Paint();
        mPaint.setAntiAlias(true);

        mTextPaint = new TextPaint();
        mTextPaint.setAntiAlias(true);
        mTextPaint.setFlags(Paint.FAKE_BOLD_TEXT_FLAG);
        mTextPaint.setTextSize(mMaxSize);

        Rect temp = new Rect();
        mTextPaint.getTextBounds("2016", 0, "2016".length(), temp);
        mYearMaxWidthDefault = temp.width();
        mTextPaint.getTextBounds("MAY", 0, "MAY".length(), temp);
        mMonthMaxWidthDefault = temp.width();
        mTextPaint.getTextBounds("28", 0, "28".length(), temp);
        mDayMaxWidthDefault = temp.width();


        Rect label = new Rect();
        mTextPaint.setTextSize(mLabelSize);
        mTextPaint.getTextBounds(mLabel, 0, mLabel.length(), label);
        mLabelHeight = label.height();

        mFloatEvaluator = new FloatEvaluator();
        mArgbEvaluator = new ArgbEvaluator();

        mRect_Year_Center = new Rect();
        mRect_Year_Pre = new Rect();
        mRect_Year_Next = new Rect();
        mRect_Year_Min = new Rect();

        mRect_Month_Center = new Rect();
        mRect_Month_Pre = new Rect();
        mRect_Month_Next = new Rect();
        mRect_Month_Min = new Rect();

        mRect_Day_Center = new Rect();
        mRect_Day_Pre = new Rect();
        mRect_Day_Next = new Rect();
        mRect_Day_Min = new Rect();

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        setMeasuredDimension(widthSize, heightSize);//use EXACTLY
        mMeasuredHeight = getMeasuredHeight();
        mMeasuredWidth = getMeasuredWidth();
        mPreNextHeight = (int) (mMeasuredHeight * mHeightRat);
        mUpdateScroll = mMeasuredHeight / 2 - mPreNextHeight / 2;

        if (mShowSet) {
            showDate(mSelectedYear, mSelectedMonth, mSelectedDay);
            mShowSet = false;
        }
    }


    @Override
    protected void onDraw(Canvas canvas) {
        //Log.i(TAG, "mDirection=" + mDirection);

        mPaint.setColor(mDividorColor);
        mPaint.setStrokeWidth(2);
        canvas.drawLine(0, mPreNextHeight, getWidth(), mPreNextHeight, mPaint);
        canvas.drawLine(0, mMeasuredHeight - mPreNextHeight, getWidth(), mMeasuredHeight - mPreNextHeight, mPaint);
        mTextPaint.setColor(Color.BLACK);
        mTextPaint.setTextSize(mLabelSize);
        canvas.drawText(mLabel, 0, mMeasuredHeight / 2 + mLabelHeight / 2, mTextPaint);

        drawYear(canvas);
        drawMonth(canvas);
        drawDay(canvas);
    }

    private void drawDay(Canvas canvas) {
        mTextPaint.setColor(mAnimColor2_Day);
        mTextPaint.setTextSize(mCenterSize_Day);
        mTextPaint.getTextBounds(mDrawDay[2], 0, mDrawDay[2].length(), mRect_Day_Center);
        int dayStartX = mMeasuredWidth - mRightGap - mYearMaxWidthDefault - mMargin - mMonthMaxWidthDefault - mMargin - mDayMaxWidthDefault;
        canvas.drawText(mDrawDay[2], dayStartX, mMeasuredHeight / 2 + mRect_Day_Center.height() / 2 + mCurScroll_Day, mTextPaint);
        if (mCurScroll_Day < 0) {
            mTextPaint.setColor(mColorPreNext);
            mTextPaint.setTextSize(mMinSize);
            mTextPaint.getTextBounds(mDrawDay[1], 0, mDrawDay[1].length(), mRect_Day_Pre);
            canvas.drawText(mDrawDay[1], dayStartX, mMeasuredHeight / 2 + mCurScroll_Day - (mMeasuredHeight / 2 - mPreNextHeight / 2) + mRect_Day_Pre.height() / 2, mTextPaint);
            mTextPaint.setColor(mAnimColor1_Day);
            mTextPaint.setTextSize(mPreNextSize_Day);////
            mTextPaint.getTextBounds(mDrawDay[3], 0, mDrawDay[3].length(), mRect_Day_Next);
            canvas.drawText(mDrawDay[3], dayStartX, mMeasuredHeight / 2 + mCurScroll_Day + (mMeasuredHeight / 2 - mPreNextHeight / 2) + mRect_Day_Next.height() / 2, mTextPaint);
        } else {
            mTextPaint.setColor(mAnimColor1_Day);
            mTextPaint.setTextSize(mPreNextSize_Day);
            mTextPaint.getTextBounds(mDrawDay[1], 0, mDrawDay[1].length(), mRect_Day_Pre);
            canvas.drawText(mDrawDay[1], dayStartX, mMeasuredHeight / 2 + mCurScroll_Day - (mMeasuredHeight / 2 - mPreNextHeight / 2) + mRect_Day_Pre.height() / 2, mTextPaint);
            mTextPaint.setColor(mColorPreNext);
            mTextPaint.setTextSize(mMinSize);////
            mTextPaint.getTextBounds(mDrawDay[3], 0, mDrawDay[3].length(), mRect_Day_Next);
            canvas.drawText(mDrawDay[3], dayStartX, mMeasuredHeight / 2 + mCurScroll_Day + (mMeasuredHeight / 2 - mPreNextHeight / 2) + mRect_Day_Next.height() / 2, mTextPaint);
        }
        mTextPaint.setColor(mColorPreNext);
        mTextPaint.setTextSize(mMinSize);
        mTextPaint.getTextBounds(mDrawDay[0], 0, mDrawDay[0].length(), mRect_Day_Min);
        canvas.drawText(mDrawDay[0], dayStartX, mMeasuredHeight / 2 + mCurScroll_Day - 2 * (mMeasuredHeight / 2 - mPreNextHeight / 2) + mRect_Day_Min.height() / 2, mTextPaint);
        mTextPaint.getTextBounds(mDrawDay[4], 0, mDrawDay[4].length(), mRect_Day_Min);
        canvas.drawText(mDrawDay[4], dayStartX, mMeasuredHeight / 2 + mCurScroll_Day + 2 * (mMeasuredHeight / 2 - mPreNextHeight / 2) + mRect_Day_Min.height() / 2, mTextPaint);
    }

    private void drawMonth(Canvas canvas) {
        mTextPaint.setColor(mAnimColor2_Month);
        mTextPaint.setTextSize(mCenterSize_Month);
        mTextPaint.getTextBounds(mDrawMonth[2], 0, mDrawMonth[2].length(), mRect_Month_Center);
        canvas.drawText(mDrawMonth[2], mMeasuredWidth - mYearMaxWidthDefault - mRightGap - mMargin - mMonthMaxWidthDefault / 2 - mRect_Month_Center.width() / 2, mMeasuredHeight / 2 + mRect_Month_Center.height() / 2 + mCurScroll_Month, mTextPaint);
        if (mCurScroll_Month < 0) {
            mTextPaint.setColor(mColorPreNext);
            mTextPaint.setTextSize(mMinSize);
            mTextPaint.getTextBounds(mDrawMonth[1], 0, mDrawMonth[1].length(), mRect_Month_Pre);
            canvas.drawText(mDrawMonth[1], mMeasuredWidth - mYearMaxWidthDefault - mRightGap - mMargin - mMonthMaxWidthDefault / 2 - mRect_Month_Pre.width() / 2, mMeasuredHeight / 2 + mCurScroll_Month - (mMeasuredHeight / 2 - mPreNextHeight / 2) + mRect_Month_Pre.height() / 2, mTextPaint);
            mTextPaint.setColor(mAnimColor1_Month);
            mTextPaint.setTextSize(mPreNextSize_Month);////
            mTextPaint.getTextBounds(mDrawMonth[3], 0, mDrawMonth[3].length(), mRect_Month_Next);
            canvas.drawText(mDrawMonth[3], mMeasuredWidth - mYearMaxWidthDefault - mRightGap - mMargin - mMonthMaxWidthDefault / 2 - mRect_Month_Next.width() / 2, mMeasuredHeight / 2 + mCurScroll_Month + (mMeasuredHeight / 2 - mPreNextHeight / 2) + mRect_Month_Next.height() / 2, mTextPaint);
        } else {
            mTextPaint.setColor(mAnimColor1_Month);
            mTextPaint.setTextSize(mPreNextSize_Month);
            mTextPaint.getTextBounds(mDrawMonth[1], 0, mDrawMonth[1].length(), mRect_Month_Pre);
            canvas.drawText(mDrawMonth[1], mMeasuredWidth - mYearMaxWidthDefault - mRightGap - mMargin - mMonthMaxWidthDefault / 2 - mRect_Month_Pre.width() / 2, mMeasuredHeight / 2 + mCurScroll_Month - (mMeasuredHeight / 2 - mPreNextHeight / 2) + mRect_Month_Pre.height() / 2, mTextPaint);
            mTextPaint.setColor(mColorPreNext);
            mTextPaint.setTextSize(mMinSize);////
            mTextPaint.getTextBounds(mDrawMonth[3], 0, mDrawMonth[3].length(), mRect_Month_Next);
            canvas.drawText(mDrawMonth[3], mMeasuredWidth - mYearMaxWidthDefault - mRightGap - mMargin - mMonthMaxWidthDefault / 2 - mRect_Month_Next.width() / 2, mMeasuredHeight / 2 + mCurScroll_Month + (mMeasuredHeight / 2 - mPreNextHeight / 2) + mRect_Month_Next.height() / 2, mTextPaint);
        }
        mTextPaint.setColor(mColorPreNext);
        mTextPaint.setTextSize(mMinSize);
        mTextPaint.getTextBounds(mDrawMonth[0], 0, mDrawMonth[0].length(), mRect_Month_Min);
        canvas.drawText(mDrawMonth[0], mMeasuredWidth - mYearMaxWidthDefault - mRightGap - mMargin - mMonthMaxWidthDefault / 2 - mRect_Month_Min.width() / 2, mMeasuredHeight / 2 + mCurScroll_Month - 2 * (mMeasuredHeight / 2 - mPreNextHeight / 2) + mRect_Month_Min.height() / 2, mTextPaint);
        mTextPaint.getTextBounds(mDrawMonth[4], 0, mDrawMonth[4].length(), mRect_Month_Min);
        canvas.drawText(mDrawMonth[4], mMeasuredWidth - mYearMaxWidthDefault - mRightGap - mMargin - mMonthMaxWidthDefault / 2 - mRect_Month_Min.width() / 2, mMeasuredHeight / 2 + mCurScroll_Month + 2 * (mMeasuredHeight / 2 - mPreNextHeight / 2) + mRect_Month_Min.height() / 2, mTextPaint);
    }

    private void drawYear(Canvas canvas) {
        mTextPaint.setColor(mAnimColor2_Year);
        mTextPaint.setTextSize(mCenterSize_Year);
        mTextPaint.getTextBounds(mDrawYear[2], 0, mDrawYear[2].length(), mRect_Year_Center);
        canvas.drawText(mDrawYear[2], mMeasuredWidth - mRect_Year_Center.width() - mRightGap, mMeasuredHeight / 2 + mRect_Year_Center.height() / 2 + mCurScroll_Year, mTextPaint);
        if (mCurScroll_Year < 0) {
            mTextPaint.setColor(mColorPreNext);
            mTextPaint.setTextSize(mMinSize);//最后加上自身高度的一半
            mTextPaint.getTextBounds(mDrawYear[1], 0, mDrawYear[1].length(), mRect_Year_Pre);
            canvas.drawText(mDrawYear[1], mMeasuredWidth - mRect_Year_Pre.width() - mRightGap, mMeasuredHeight / 2 + mCurScroll_Year - (mMeasuredHeight / 2 - mPreNextHeight / 2) + mRect_Year_Pre.height() / 2, mTextPaint);
            mTextPaint.setColor(mAnimColor1_Year);
            mTextPaint.setTextSize(mPreNextSize_Year);////
            mTextPaint.getTextBounds(mDrawYear[3], 0, mDrawYear[3].length(), mRect_Year_Next);
            canvas.drawText(mDrawYear[3], mMeasuredWidth - mRect_Year_Next.width() - mRightGap, mMeasuredHeight / 2 + mCurScroll_Year + (mMeasuredHeight / 2 - mPreNextHeight / 2) + mRect_Year_Next.height() / 2, mTextPaint);
        } else {
            mTextPaint.setColor(mAnimColor1_Year);
            mTextPaint.setTextSize(mPreNextSize_Year);
            mTextPaint.getTextBounds(mDrawYear[1], 0, mDrawYear[1].length(), mRect_Year_Pre);
            canvas.drawText(mDrawYear[1], mMeasuredWidth - mRect_Year_Pre.width() - mRightGap, mMeasuredHeight / 2 + mCurScroll_Year - (mMeasuredHeight / 2 - mPreNextHeight / 2) + mRect_Year_Pre.height() / 2, mTextPaint);
            mTextPaint.setColor(mColorPreNext);
            mTextPaint.setTextSize(mMinSize);////
            mTextPaint.getTextBounds(mDrawYear[3], 0, mDrawYear[3].length(), mRect_Year_Next);
            canvas.drawText(mDrawYear[3], mMeasuredWidth - mRect_Year_Next.width() - mRightGap, mMeasuredHeight / 2 + mCurScroll_Year + (mMeasuredHeight / 2 - mPreNextHeight / 2) + mRect_Year_Next.height() / 2, mTextPaint);
        }
        mTextPaint.setColor(mColorPreNext);
        mTextPaint.setTextSize(mMinSize);
        mTextPaint.getTextBounds(mDrawYear[0], 0, mDrawYear[0].length(), mRect_Year_Min);
        canvas.drawText(mDrawYear[0], mMeasuredWidth - mRect_Year_Min.width() - mRightGap, mMeasuredHeight / 2 + mCurScroll_Year - 2 * (mMeasuredHeight / 2 - mPreNextHeight / 2) + mRect_Year_Min.height() / 2, mTextPaint);
        mTextPaint.getTextBounds(mDrawYear[4], 0, mDrawYear[4].length(), mRect_Year_Min);
        canvas.drawText(mDrawYear[4], mMeasuredWidth - mRect_Year_Min.width() - mRightGap, mMeasuredHeight / 2 + mCurScroll_Year + 2 * (mMeasuredHeight / 2 - mPreNextHeight / 2) + mRect_Year_Min.height() / 2, mTextPaint);
    }

    public void showDate(int year, int month, int day) {
        mShowSet = true;
        rebuildYear();
        rebuildMonth();
        rebuildDay();
        invalidateCurDate(year, month, day);
        invalidate();
    }

    private void invalidateCurDate(int year, int month, int day) {
        mSelectedYear = year;

        int willMonth;
        if (month > 12) {
            willMonth = 1;
        } else if (month < 1) {
            willMonth = 12;
        } else {
            willMonth = month;
        }
        mSelectedMonth = willMonth;

        int willDay;
        int maxDay;
        if (mSelectedMonth == 2 && isLeapYear(mSelectedYear)) {
            maxDay = 29;
        } else {
            maxDay = maxDayArray[mSelectedMonth - 1];
        }
        if (day > maxDay) {
            willDay = 1;
        } else if (day < 1) {
            willDay = maxDay;
        } else {
            willDay = day;
        }
        mSelectedDay = willDay;

        mDrawYear[2] = Integer.toString(year);
        mDrawMonth[2] = monthArray[checkMonthArr(willMonth - 1)];
        mDrawDay[2] = addZero(checkDay(willDay, maxDay));
        //月份天监测，闰平年监测
        mDrawYear[1] = Integer.toString(year - 1);
        mDrawMonth[1] = monthArray[checkMonthArr(willMonth - 2)];
        mDrawDay[1] = addZero(checkDay(willDay - 1, maxDay));

        mDrawYear[0] = Integer.toString(year - 2);
        mDrawMonth[0] = monthArray[checkMonthArr(willMonth - 3)];
        mDrawDay[0] = addZero(checkDay(willDay - 2, maxDay));

        mDrawYear[3] = Integer.toString(year + 1);
        mDrawMonth[3] = monthArray[checkMonthArr(willMonth)];
        mDrawDay[3] = addZero(checkDay(willDay + 1, maxDay));

        mDrawYear[4] = Integer.toString(year + 2);
        mDrawMonth[4] = monthArray[checkMonthArr(willMonth + 1)];
        mDrawDay[4] = addZero(checkDay(willDay + 2, maxDay));

    }

    private int checkMonthArr(int arrIndex) {
        if (arrIndex - 11 == 1) {
            return 0;
        } else if (arrIndex - 11 == 2) {
            return 1;
        } else if (arrIndex == -1) {
            return 11;
        } else if (arrIndex == -2) {
            return 10;
        }
        return arrIndex;
    }

    private int checkDay(int day, int maxDay) {
        if (day - maxDay == 1) {
            return 1;
        } else if (day - maxDay == 2) {
            return 2;
        } else if (day == 0) {
            return maxDay;
        } else if (day == -1) {
            return maxDay - 1;
        }
        return day;
    }

    private String addZero(int num) {
        if (num <= 9) {
            return "0" + Integer.toString(num);
        }
        return Integer.toString(num);
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mTouchMode = 1;
                if (mIsFilling == false) {// not filling , not anim
                    mInteractivePicker = getOpArea((int) event.getX());
                }
                mOldY = (int) event.getY();
                if (!mScroller.isFinished()) {
                    mScroller.abortAnimation();
                }
                break;
            case MotionEvent.ACTION_MOVE:
                mTouchMode = 2;
                mNewY = (int) event.getY();
                int dy = mNewY - mOldY;

                if (mNewY > mOldY) {//↓
                    mDirection = -1;
                } else if (mNewY < mOldY) {//↑
                    mDirection = 1;
                }

                mEvent = event;
                invalidateYear(dy, event);
                invalidateMonth(dy, event);
                invalidateDay(dy, event);
                invalidate();

                mVelocityTracker.addMovement(event);
                mVelocityTracker.computeCurrentVelocity(1000);
                mLastXVelocity = mVelocityTracker.getYVelocity();

                mOldY = mNewY;
                break;
            case MotionEvent.ACTION_UP:
                mTouchMode = 3;
                mScroller.fling(0, 0, 0, (int) mLastXVelocity, 0, 0, Integer.MIN_VALUE, Integer.MAX_VALUE);
                //if (mCurScroll_Year != 0) animYear();
                //if (mCurScroll_Month != 0) animMonth();
                //if (mCurScroll_Day != 0) animDay();
                invalidate();
                break;
            case MotionEvent.ACTION_CANCEL:
                Log.i(TAG, "cancel");
                break;
        }
        return true;
    }

    private void animYear() {
        int dir = 0;//-1:↑ 1:↓
        if (mCurScroll_Year <= mUpdateScroll / 2 && mCurScroll_Year >= -mUpdateScroll / 2) {
            valueAnimator_Year = ValueAnimator.ofInt(mCurScroll_Year, 0);
        }
        if (mCurScroll_Year < -mUpdateScroll / 2) {
            valueAnimator_Year = ValueAnimator.ofInt(mCurScroll_Year, -mUpdateScroll);
            dir = -1;
        }
        if (mCurScroll_Year > mUpdateScroll / 2) {
            valueAnimator_Year = ValueAnimator.ofInt(mCurScroll_Year, mUpdateScroll);
            dir = 1;
        }
        valueAnimator_Year.setDuration(mAnimDuration);
        valueAnimator_Year.start();
        valueAnimator_Year.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mCurScroll_Year = (int) animation.getAnimatedValue();
                mCurScroll_Year = Math.abs(mCurScroll_Year) == mUpdateScroll ? 0 : mCurScroll_Year;
                rebuildYear();
                invalidate();
            }
        });
        valueAnimator_Year.addListener(new MyAnimAdapter(dir) {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                mIsAdjustingAnim_Year = false;
                switch (dir) {
                    case -1:
                        invalidateCurDate(mSelectedYear + 1, mSelectedMonth, mSelectedDay);
                        break;
                    case 1:
                        invalidateCurDate(mSelectedYear - 1, mSelectedMonth, mSelectedDay);
                        break;
                    case 0:
                        break;
                }
                callback();
            }
        });
    }

    private void animMonth() {
        int dir = 0;//-1:↑ 1:↓
        if (mCurScroll_Month <= mUpdateScroll / 2 && mCurScroll_Month >= -mUpdateScroll / 2) {
            valueAnimator_Month = ValueAnimator.ofInt(mCurScroll_Month, 0);
        }
        if (mCurScroll_Month < -mUpdateScroll / 2) {
            valueAnimator_Month = ValueAnimator.ofInt(mCurScroll_Month, -mUpdateScroll);
            dir = -1;
        }
        if (mCurScroll_Month > mUpdateScroll / 2) {
            valueAnimator_Month = ValueAnimator.ofInt(mCurScroll_Month, mUpdateScroll);
            dir = 1;
        }
        valueAnimator_Month.setDuration(mAnimDuration);
        valueAnimator_Month.start();
        valueAnimator_Month.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mCurScroll_Month = (int) animation.getAnimatedValue();
                mCurScroll_Month = Math.abs(mCurScroll_Month) == mUpdateScroll ? 0 : mCurScroll_Month;
                rebuildMonth();
                invalidate();
            }
        });
        valueAnimator_Month.addListener(new MyAnimAdapter(dir) {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                mIsAdjustingAnim_Month = false;
                switch (dir) {
                    case -1:
                        invalidateCurDate(mSelectedYear, mSelectedMonth + 1, mSelectedDay);
                        break;
                    case 1:
                        invalidateCurDate(mSelectedYear, mSelectedMonth - 1, mSelectedDay);
                        break;
                    case 0:
                        break;
                }
                callback();
            }
        });
    }

    private void animDay() {
        int dir = 0;//-1:↑ 1:↓
        if (mCurScroll_Day <= mUpdateScroll / 2 && mCurScroll_Day >= -mUpdateScroll / 2) {
            valueAnimator_Day = ValueAnimator.ofInt(mCurScroll_Day, 0);
        }
        if (mCurScroll_Day < -mUpdateScroll / 2) {
            valueAnimator_Day = ValueAnimator.ofInt(mCurScroll_Day, -mUpdateScroll);
            dir = -1;
        }
        if (mCurScroll_Day > mUpdateScroll / 2) {
            valueAnimator_Day = ValueAnimator.ofInt(mCurScroll_Day, mUpdateScroll);
            dir = 1;
        }
        valueAnimator_Day.setDuration(mAnimDuration);
        valueAnimator_Day.start();
        valueAnimator_Day.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mCurScroll_Day = (int) animation.getAnimatedValue();
                mCurScroll_Day = Math.abs(mCurScroll_Day) == mUpdateScroll ? 0 : mCurScroll_Day;
                rebuildDay();
                invalidate();
            }
        });
        valueAnimator_Day.addListener(new MyAnimAdapter(dir) {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                mIsAdjustingAnim_Day = false;
                switch (dir) {
                    case -1:
                        invalidateCurDate(mSelectedYear, mSelectedMonth, mSelectedDay + 1);
                        break;
                    case 1:
                        invalidateCurDate(mSelectedYear, mSelectedMonth, mSelectedDay - 1);
                        break;
                    case 0:
                        break;
                }
                callback();
            }
        });
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (valueAnimator_Year != null) {
            valueAnimator_Year.cancel();
            valueAnimator_Year.removeAllListeners();
        }
        if (valueAnimator_Month != null) {
            valueAnimator_Month.cancel();
            valueAnimator_Month.removeAllListeners();
        }
        if (valueAnimator_Day != null) {
            valueAnimator_Day.cancel();
            valueAnimator_Day.removeAllListeners();
        }
    }

    private void invalidateYear(int dy, MotionEvent event) {
        int x = (int) event.getX();
        if (mInteractivePicker != 3) return;

        mCurScroll_Year += dy;
        if (mCurScroll_Year > mUpdateScroll || mCurScroll_Year + dy > mUpdateScroll) {
            mCurScroll_Year = mUpdateScroll;
            invalidateCurDate(Integer.parseInt(mDrawYear[2]) - 1, mSelectedMonth, mSelectedDay);//test year
            mCurScroll_Year = 0;
        } else if (mCurScroll_Year < -mUpdateScroll || mCurScroll_Year + dy < -mUpdateScroll) {
            mCurScroll_Year = -mUpdateScroll;
            invalidateCurDate(Integer.parseInt(mDrawYear[2]) + 1, mSelectedMonth, mSelectedDay);//test year
            mCurScroll_Year = 0;
        }

        rebuildYear();
    }

    private void rebuildYear() {
        mPreNextSize_Year = mFloatEvaluator.evaluate((float) (Math.abs(mCurScroll_Year)) / mUpdateScroll, mMinSize, mMaxSize);
        mCenterSize_Year = mFloatEvaluator.evaluate((float) (Math.abs(mCurScroll_Year)) / mUpdateScroll, mMaxSize, mMinSize);
        mAnimColor1_Year = (int) mArgbEvaluator.evaluate((float) (Math.abs(mCurScroll_Year)) / mUpdateScroll, mColorPreNext, mSelectedColor);
        mAnimColor2_Year = (int) mArgbEvaluator.evaluate((float) (Math.abs(mCurScroll_Year)) / mUpdateScroll, mSelectedColor, mColorPreNext);
    }

    private void invalidateMonth(int dy, MotionEvent event) {
        int x = (int) event.getX();
        if (mInteractivePicker != 2) return;

        mCurScroll_Month += dy;
        if (mCurScroll_Month > mUpdateScroll || mCurScroll_Month + dy > mUpdateScroll) {
            mCurScroll_Month = mUpdateScroll;
            invalidateCurDate(mSelectedYear, mSelectedMonth - 1, mSelectedDay);//test month
            mCurScroll_Month = 0;
        } else if (mCurScroll_Month < -mUpdateScroll || mCurScroll_Month + dy < -mUpdateScroll) {
            mCurScroll_Month = -mUpdateScroll;
            invalidateCurDate(mSelectedYear, mSelectedMonth + 1, mSelectedDay);//test month
            mCurScroll_Month = 0;
        }
        rebuildMonth();
    }

    private void rebuildMonth() {
        mPreNextSize_Month = mFloatEvaluator.evaluate((float) (Math.abs(mCurScroll_Month)) / mUpdateScroll, mMinSize, mMaxSize);
        mCenterSize_Month = mFloatEvaluator.evaluate((float) (Math.abs(mCurScroll_Month)) / mUpdateScroll, mMaxSize, mMinSize);
        mAnimColor1_Month = (int) mArgbEvaluator.evaluate((float) (Math.abs(mCurScroll_Month)) / mUpdateScroll, mColorPreNext, mSelectedColor);
        mAnimColor2_Month = (int) mArgbEvaluator.evaluate((float) (Math.abs(mCurScroll_Month)) / mUpdateScroll, mSelectedColor, mColorPreNext);
    }

    private void invalidateDay(int dy, MotionEvent event) {
        int x = (int) event.getX();
        if (mInteractivePicker != 1) return;

        mCurScroll_Day += dy;
        if (mCurScroll_Day > mUpdateScroll || mCurScroll_Day + dy > mUpdateScroll) {
            mCurScroll_Day = mUpdateScroll;
            invalidateCurDate(mSelectedYear, mSelectedMonth, mSelectedDay - 1);//test day
            mCurScroll_Day = 0;
        } else if (mCurScroll_Day < -mUpdateScroll || mCurScroll_Day + dy < -mUpdateScroll) {
            mCurScroll_Day = -mUpdateScroll;
            invalidateCurDate(mSelectedYear, mSelectedMonth, mSelectedDay + 1);//test day
            mCurScroll_Day = 0;
        }
        rebuildDay();
    }

    private void rebuildDay() {
        mPreNextSize_Day = mFloatEvaluator.evaluate((float) (Math.abs(mCurScroll_Day)) / mUpdateScroll, mMinSize, mMaxSize);
        mCenterSize_Day = mFloatEvaluator.evaluate((float) (Math.abs(mCurScroll_Day)) / mUpdateScroll, mMaxSize, mMinSize);
        mAnimColor1_Day = (int) mArgbEvaluator.evaluate((float) (Math.abs(mCurScroll_Day)) / mUpdateScroll, mColorPreNext, mSelectedColor);
        mAnimColor2_Day = (int) mArgbEvaluator.evaluate((float) (Math.abs(mCurScroll_Day)) / mUpdateScroll, mSelectedColor, mColorPreNext);
    }

    private boolean isLeapYear(int year) {
        if (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0)) {
            return true;
        }
        return false;
    }

    interface IDatePicker {
        void onDateSelected(int viewId, int day, int month, int year);
    }

    public void setDatePickerListener(IDatePicker mIDatePicker) {
        this.mIDatePicker = mIDatePicker;
    }

    private void callback() {
        if (mIDatePicker != null)
            mIDatePicker.onDateSelected(getId(), mSelectedDay, mSelectedMonth, mSelectedYear);
    }

    class MyAnimAdapter extends AnimatorListenerAdapter {
        int dir;

        public MyAnimAdapter(int dir) {
            this.dir = dir;
        }
    }

    @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()) {
            //Log.i(TAG,"filling");
            mIsFilling = true;
            mNewFilling = mScroller.getCurrY();
            mFillingDy = Math.abs(mNewFilling - mOldFilling);
            mFillingDy = mFillingDy > mUpdateScroll ? mUpdateScroll : mFillingDy;
            mFillingDy = mDirection == -1 ? mFillingDy : -mFillingDy;
            mOldFilling = mNewFilling;

            invalidateYear(mFillingDy, mEvent);
            invalidateMonth(mFillingDy, mEvent);
            invalidateDay(mFillingDy, mEvent);

            postInvalidate();
        } else if (mScroller.computeScrollOffset() == false) {
            mIsFilling = false;
            if (mCurScroll_Year != 0 && mIsAdjustingAnim_Year == false && mTouchMode == 3) {
                mIsAdjustingAnim_Year = true;
                animYear();
            }
            if (mCurScroll_Month != 0 && mIsAdjustingAnim_Month == false && mTouchMode == 3) {
                mIsAdjustingAnim_Month = true;
                animMonth();
            }
            if (mCurScroll_Day != 0 && mIsAdjustingAnim_Day == false && mTouchMode == 3) {
                mIsAdjustingAnim_Day = true;
                animDay();
            }
            callback();
        }
    }

    /**
     * 获得操作的datepicker类型（1:day 2:month 3:year）
     * none:0
     *
     * @param event_x
     * @return
     */
    private int getOpArea(int event_x) {
        if (event_x < mMeasuredWidth - mRightGap - mYearMaxWidthDefault - mMargin - mMonthMaxWidthDefault - mMargin / 2) {
            return 1;
        } else if (event_x <= mMeasuredWidth - (mRightGap + mYearMaxWidthDefault + mMargin / 2) && event_x >= mMeasuredWidth - (mRightGap + mYearMaxWidthDefault + mMargin + mMonthMaxWidthDefault + mMargin / 2)) {
            return 2;
        } else if (event_x > mMeasuredWidth - (mRightGap + mYearMaxWidthDefault + mMargin / 2)) {
            return 3;
        }
        return 0;
    }

}
